//-----------------------------------------------------------------------
// <copyright file="NDoc.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Calls NDoc in order to generate compiled HTML documentation for the specified assemblies.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Tools
{
    using System;
    using System.Xml;
    using System.Globalization;
    using System.IO;
    using System.Text.RegularExpressions;
    using Microsoft.Win32;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Tasks;
    using Microsoft.Build.Utilities;


    /// <summary>
    /// Calls NDoc in order to generate compiled HTML documentation for the specified assemblies.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <Tools.NDoc Assemblies="assemblies"
    ///              ProjectFilePath="projectFilePath"
    ///              OutputFilePath="outputFilePath"
    ///              Documenter="documenter">
    /// </Tools.NDoc>
    /// ]]></code>
    /// <para>where:</para>
    /// <para><i>assemblies (Required)</i></para>
    /// <para>The fullpaths to the assemblies to create docs for.</para>
    /// <para><i>projectFilePath (Required)</i></para>
    /// <para>This will be the NDoc file that will be used as a template.</para>
    /// <para><i>outputFilePath (Required)</i></para>
    /// <para>The name of the folder to create all the compiled help docs in.</para>
    /// <para><i>documenter (Optional)</i></para>
    /// <para>The NDoc documenter to use. Available documenters are VS.NET_2003, JavaDoc, LaTeX, LinearHtml, MSDN, XML.</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <ItemGroup>
    ///         <Assemblies Include="Microsoft.Sdc.Tasks.Configuration.Tasks.dll" />
    ///         <Assemblies Include="Microsoft.Sdc.Tasks.Configuration.Tasks.Test.dll" />
    ///     </ItemGroup>
    ///     <Target Name="Test" >
    ///         <Tools.NDoc
    ///             ProjectFilePath="$(MSBuildProjectDirectory)\NDoc\Microsoft.Sdc.Tasks.Configuration.NDoc" 
    ///             OutputFilePath="$(TEMP)\Main\NDocOutput" 
    ///             Assemblies="@(Assemblies->'%(FullPath)')"
    ///             Documenter="MSDN">
    ///         </Tools.NDoc>
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class NDoc : ToolTaskBase
    {
        /// <summary>
        /// Initializes a new instance of the NDoc class.
        /// </summary>
        public NDoc()
        {
        }

        /// <summary>
        /// The name of the exe we call.
        /// </summary>
        /// <value>The name of the exe we call.</value>
        protected override string ToolName
        {
            get { return "NDocConsole.exe"; }
        }

        /// <summary>
        /// Full calculated path to tool including exe name
        /// </summary>
        /// <returns>Defaults to default install location of FxCop</returns>
        protected override string GenerateFullPathToTool()
        {
            return System.IO.Path.Combine(this.GetPathToNDoc(), this.ToolName);
        }       

        /// <summary>
        /// Builds the commandline for this tool
        /// </summary>
        /// <param name="commandLine">The object to append the args to.</param>
        /// <returns>True if successfully added args.</returns>
        protected override void AddCommandLineCommands(CommandLineBuilderExtension commandLine)
        {

            AppendSwitchAndValueWhenNotStringEmpty(commandLine, "-documenter", "Documenter", "=");
            AppendSwitchAndValueWhenNotStringEmpty(commandLine, "-project", "ProjectFilePath", "=");
            AppendSwitchAndValueWhenNotStringEmpty(commandLine, "-OutputDirectory", "OutputFilePath", "=");
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            #region Execute code

            //Create HTML MSDN-style documents (.CHM)
            Log.LogMessageFromResources("Ndoc.CreatingDocumentation");

            if (!SetUpNDocProject(this.Assemblies, this.ProjectFilePath))
            {
                throw new TaskException("Ndoc.ProjectSetupFailed", this.ProjectFilePath);
            }            

            Directory.CreateDirectory(this.OutputFilePath);
            
            base.InternalExecute();
            
            #endregion
        }

        private bool SetUpNDocProject(string[] assemblies, string projectFilePath)
        {

            Log.LogMessageFromResources(MessageImportance.Low, "Ndoc.AssembliesIncluded");
            foreach (string filename in assemblies)
            {
                Log.LogMessage(MessageImportance.Low, filename);
            }

            //What if assemblies has no elements?
            if (assemblies.Length == 0)
            {
                Log.LogError("Ndoc.NoAssembliesFound");
                return false;
            }

            XmlDocument masterXml = new XmlDocument();
            masterXml.Load(projectFilePath);

            XmlNode targetNode = masterXml.SelectSingleNode("project/assemblies");
            if (targetNode == null)
            {
                Log.LogError("Ndoc.ErrorLocatingAssemblies");
                return false;
            }
            targetNode.RemoveAll();

            foreach (string assembly in assemblies)
            {
                XmlElement newElem = masterXml.CreateElement("assembly");
                XmlAttribute newAttr = masterXml.CreateAttribute("location");
                newAttr.Value = assembly;
                newElem.SetAttributeNode(newAttr);

                newAttr = masterXml.CreateAttribute("documentation");
                //TODO Should use te path class here to do this
                string documentationFile = assembly.Substring(0, assembly.Length - 4) + ".xml";
                if (System.IO.File.Exists(documentationFile))
                {
                    newAttr.Value = documentationFile;
                    newElem.SetAttributeNode(newAttr);
                    targetNode.AppendChild(newElem);
                }
                else
                {
                    Log.LogError("Ndoc.MissingXmlFile", documentationFile);
                    return false;
                }
            }

            //Save the document
            //set set the attrbutes back to what they were not just read only
            FileInfo fi = new FileInfo(projectFilePath);
            FileAttributes oldAttributes = fi.Attributes;
            fi.Attributes = FileAttributes.Normal;
            masterXml.Save(projectFilePath);
            fi.Attributes = oldAttributes;
            return true;
        }

        private string GetPathToNDoc()
        {
            //@"C:\Program Files\NDoc";
            try
            {
                string s;

                RegistryKey nDocKey = Registry.ClassesRoot.OpenSubKey(@"ndoc\shell\Open\Command");
                string pathToNDoc = Convert.ToString(nDocKey.GetValue(""), CultureInfo.InvariantCulture);
                nDocKey.Close();
                Regex regex = new Regex(@"(.+)NDocGui\.exe.+", RegexOptions.IgnoreCase);
                Match m = regex.Match(pathToNDoc);
                s = m.Groups[1].Value;
                s = s.Replace("\"", "");

                Log.LogMessageFromResources(MessageImportance.Low, "Ndoc.Path", s);
                return s;
            }
            catch
            {
                Log.LogMessageFromResources(MessageImportance.Low, "Ndoc.NoRegKey");
                return System.Environment.ExpandEnvironmentVariables(@"%ProgramFiles%\NDoc");
            }
        }

        [Required]
        public string ProjectFilePath
        {
            get { return (string) Bag["ProjectFilePath"]; }
            set { Bag["ProjectFilePath"] = value; }
        }

        [Required]
        public string OutputFilePath
        {
            get { return (string) Bag["OutputFilePath"]; }
            set { Bag["OutputFilePath"] = value; }
        }

        [Required]
        public string[] Assemblies
        {
            get { return ((string[]) Bag["Assemblies"]); }
            set { Bag["Assemblies"] = value; }
        }

        /// <summary>
        /// This propertypasses through to the NDoc command line, setting the "documenter" command line switch. As such valid values for this attribute are VS.NET_2003, JavaDoc, LaTeX, LinearHtml, MSDN, XML.
        /// Leaving the property unset will default the value to "MSDN".
        /// </summary>
        /// <value>The NDoc documenter to use. Available documenters are VS.NET_2003, JavaDoc, LaTeX, LinearHtml, MSDN, XML.</value>
        public string Documenter
        {
            get { return ((string)Bag["Documenter"]); }
            set { Bag["Documenter"] = value; }
        }
    }
}